package com.ryqg.jiaofu.config.security.provider;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ryqg.jiaofu.business.service.UserService;
import com.ryqg.jiaofu.config.security.UserDetailsImpl;
import com.ryqg.jiaofu.config.security.token.WechatAuthenticationToken;
import com.ryqg.jiaofu.domain.model.UserCredentials;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

@RequiredArgsConstructor
public class WechatAuthenticationProvider implements AuthenticationProvider {

    private final WxMaService wxMaService;

    private final UserService userService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String code = authentication.getPrincipal().toString();
        WxMaJscode2SessionResult sessionInfo;
        try {
            sessionInfo = wxMaService.getUserService().getSessionInfo(code);
        } catch (WxErrorException e) {
            throw new CredentialsExpiredException("微信登录 code 无效或已失效，请重新获取");
        }
        if (ObjectUtil.isNull(sessionInfo) || StrUtil.isBlank(sessionInfo.getOpenid())) {
            throw new UsernameNotFoundException("未能获取到微信 OpenID，请稍后重试");
        }
        String openid = sessionInfo.getOpenid();
        UserCredentials userCredentials = userService.getAuthCredentialsByOpenId(openid);
        if (ObjectUtil.isNull(userCredentials)) {
            userService.registerOrBindWechatUser(openid);
        }

        // 再次查询用户信息，确保用户注册成功
        userCredentials = userService.getAuthCredentialsByOpenId(openid);
        if (userCredentials == null) {
            throw new UsernameNotFoundException("用户注册失败，请稍后重试");
        }

        UserDetailsImpl userDetails = new UserDetailsImpl(userCredentials);
        return WechatAuthenticationToken.authenticated(userDetails, userDetails.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return (WechatAuthenticationToken.class.isAssignableFrom(authentication));
    }
}
